package com.cchr.donation;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import javax.xml.datatype.DatatypeFactory;
import javax.xml.datatype.XMLGregorianCalendar;
import com.cchr.donation.model.DonationRecord;
import net.authorize.Environment;
import net.authorize.api.contract.v1.ARBCreateSubscriptionRequest;
import net.authorize.api.contract.v1.ARBCreateSubscriptionResponse;
import net.authorize.api.contract.v1.ARBSubscriptionType;
import net.authorize.api.contract.v1.ARBSubscriptionUnitEnum;
import net.authorize.api.contract.v1.CreateTransactionRequest;
import net.authorize.api.contract.v1.CreateTransactionResponse;
import net.authorize.api.contract.v1.CreditCardType;
import net.authorize.api.contract.v1.CustomerAddressType;
import net.authorize.api.contract.v1.CustomerDataType;
import net.authorize.api.contract.v1.CustomerType;
import net.authorize.api.contract.v1.MerchantAuthenticationType;
import net.authorize.api.contract.v1.MessageTypeEnum;
import net.authorize.api.contract.v1.MessagesType;
import net.authorize.api.contract.v1.NameAndAddressType;
import net.authorize.api.contract.v1.PaymentScheduleType;
import net.authorize.api.contract.v1.MessagesType.Message;
import net.authorize.api.contract.v1.OrderType;
import net.authorize.api.contract.v1.PaymentType;
import net.authorize.api.contract.v1.TransactionRequestType;
import net.authorize.api.contract.v1.TransactionResponse;
import net.authorize.api.contract.v1.TransactionResponse.Errors;
import net.authorize.api.contract.v1.TransactionTypeEnum;
import net.authorize.api.controller.ARBCreateSubscriptionController;
import net.authorize.api.controller.CreateTransactionController;
import net.authorize.api.controller.base.ApiOperationBase;

public class AuthorizeCheckOut {

	public static final String ERROR_DEFAULT = "The transaction was unsuccessful.";
	public static final String ENV_PROD = "PROD";
	public static final int DEFAULT_OCCRRENCES=9999 ;

	public ResultEntity creditCardCheckOut(String env, String loginId, String key, CreditCardType creditCard,
			DonationRecord donationRecord, Product product) {
		ResultEntity result = new ResultEntity();
		result.setCode(ResultEntity.FAIL_CODE);
		List<String> errorList = new ArrayList<String>();
		// Common code to set for all requests
		if (env.equalsIgnoreCase(ENV_PROD)) {
			ApiOperationBase.setEnvironment(Environment.PRODUCTION);
		} else {
			ApiOperationBase.setEnvironment(Environment.SANDBOX);
		}

		MerchantAuthenticationType merchantAuthenticationType = new MerchantAuthenticationType();
		merchantAuthenticationType.setName(loginId);
		merchantAuthenticationType.setTransactionKey(key);
		ApiOperationBase.setMerchantAuthentication(merchantAuthenticationType);

		// Populate the payment data
		PaymentType paymentType = new PaymentType();
		paymentType.setCreditCard(creditCard);

		// Create the payment transaction request
		TransactionRequestType txnRequest = new TransactionRequestType();
		txnRequest.setTransactionType(TransactionTypeEnum.AUTH_CAPTURE_TRANSACTION.value());
		txnRequest.setPayment(paymentType);
		txnRequest.setAmount(donationRecord.getDonationAmt());

		OrderType orderType = new OrderType();
		orderType.setDescription(product.getName());

		txnRequest.setOrder(orderType);
		CustomerAddressType billInfo = new CustomerAddressType();
		billInfo.setFirstName(donationRecord.getFirstName());
		billInfo.setLastName(donationRecord.getLastName());
		billInfo.setAddress(donationRecord.getAddress());
		billInfo.setCity(donationRecord.getCity());
		billInfo.setState(donationRecord.getState());
		billInfo.setZip(donationRecord.getZip());
		billInfo.setCountry(donationRecord.getCountry());
		billInfo.setPhoneNumber(donationRecord.getPhone());
		billInfo.setEmail(donationRecord.getEmail());
		txnRequest.setBillTo(billInfo);

		CustomerDataType customer = new CustomerDataType();
		customer.setEmail(donationRecord.getEmail());
		txnRequest.setCustomer(customer);

		// Make the API Request
		CreateTransactionRequest apiRequest = new CreateTransactionRequest();
		apiRequest.setTransactionRequest(txnRequest);
		CreateTransactionController controller = new CreateTransactionController(apiRequest);
		controller.execute();

		CreateTransactionResponse response = controller.getApiResponse();

		if (response != null) {

			// If API Response is ok, go ahead and check the transaction
			// response
			if (response.getMessages().getResultCode() == MessageTypeEnum.OK) {

				TransactionResponse transRep = response.getTransactionResponse();
				if (transRep.getResponseCode().equals("1")) {
					result.setCode(ResultEntity.SUCCESS_CODE);
					result.setCardNumber(response.getTransactionResponse().getAccountNumber());
				}
			}

			if (result.getCode().equalsIgnoreCase(ResultEntity.FAIL_CODE)) {
				if (response.getTransactionResponse().getErrors() != null) {
					Errors errors = response.getTransactionResponse().getErrors();

					for (TransactionResponse.Errors.Error error : errors.getError()) {
						errorList.add(error.getErrorText());
					}
					result.setCode(ResultEntity.FAIL_CODE);
				}
			}
		} else {
			if (controller.getErrorResponse() != null) {
				if (controller.getErrorResponse().getMessages() != null) {
					for (Message mess : controller.getErrorResponse().getMessages().getMessage()) {
						errorList.add(mess.getText());
					}
					result.setCode(ResultEntity.FAIL_CODE);
				}
			}

		}

		if (result.getCode().equalsIgnoreCase(ResultEntity.FAIL_CODE)) {
			if (errorList.size() == 0) {
				errorList.add(ERROR_DEFAULT);
			}
			result.setMessage(errorList);
		}

		return result;
	}

	public ResultEntity createSubscription(String env, String loginId, String key, CreditCardType creditCard,
			DonationRecord donationRecord, Product product) {
		ResultEntity result = new ResultEntity();
		result.setCode(ResultEntity.FAIL_CODE);
		List<String> errorList = new ArrayList<String>();

		// Common code to set for all requests
		if (env.equalsIgnoreCase(ENV_PROD)) {
			ApiOperationBase.setEnvironment(Environment.PRODUCTION);
		} else {
			ApiOperationBase.setEnvironment(Environment.SANDBOX);
		}

		MerchantAuthenticationType merchantAuthenticationType = new MerchantAuthenticationType();
		merchantAuthenticationType.setName(loginId);
		merchantAuthenticationType.setTransactionKey(key);
		ApiOperationBase.setMerchantAuthentication(merchantAuthenticationType);

		// Set up payment schedule
		PaymentScheduleType schedule = new PaymentScheduleType();
		PaymentScheduleType.Interval interval = new PaymentScheduleType.Interval();
		interval.setLength((short) 1);
		interval.setUnit(ARBSubscriptionUnitEnum.MONTHS);
		schedule.setInterval(interval);

		try {
			XMLGregorianCalendar startDate = DatatypeFactory.newInstance().newXMLGregorianCalendar();
			Calendar calendar = Calendar.getInstance();
			calendar.setTime(new Date());
			calendar.set(Calendar.DAY_OF_MONTH, calendar.get(Calendar.DAY_OF_MONTH));// add
																						// one
																						// day
			startDate.setDay(calendar.get(Calendar.DAY_OF_MONTH));
			startDate.setMonth(calendar.get(Calendar.MONTH) + 1);
			startDate.setYear(calendar.get(Calendar.YEAR));
			schedule.setStartDate(startDate);
		} catch (Exception e) {

		}

		schedule.setTotalOccurrences((short) DEFAULT_OCCRRENCES);
		// schedule.setTrialOccurrences((short)1);

		// Populate the payment data
		PaymentType paymentType = new PaymentType();
		paymentType.setCreditCard(creditCard);

		ARBSubscriptionType arbSubscriptionType = new ARBSubscriptionType();
		arbSubscriptionType.setPaymentSchedule(schedule);
		arbSubscriptionType.setAmount(donationRecord.getDonationAmt());
		arbSubscriptionType.setName(product.getName());
		// arbSubscriptionType.setTrialAmount(new BigDecimal(1)); ////////
		arbSubscriptionType.setPayment(paymentType);

		NameAndAddressType billInfo = new NameAndAddressType();
		billInfo.setFirstName(donationRecord.getFirstName());
		billInfo.setLastName(donationRecord.getLastName());
		billInfo.setAddress(donationRecord.getAddress());
		billInfo.setCity(donationRecord.getCity());
		billInfo.setState(donationRecord.getState());
		billInfo.setZip(donationRecord.getZip());
		billInfo.setCountry(donationRecord.getCountry());
		arbSubscriptionType.setBillTo(billInfo);

		CustomerType customer = new CustomerType();
		customer.setEmail(donationRecord.getEmail());
		customer.setPhoneNumber(donationRecord.getPhone());
		arbSubscriptionType.setCustomer(customer);

		// Make the API Request
		ARBCreateSubscriptionRequest apiRequest = new ARBCreateSubscriptionRequest();
		apiRequest.setSubscription(arbSubscriptionType);
		ARBCreateSubscriptionController controller = new ARBCreateSubscriptionController(apiRequest);
		controller.execute();
		ARBCreateSubscriptionResponse response = controller.getApiResponse();

		if (response != null) {

			// If API Response is ok, go ahead and check the transaction
			// response
			if (response.getMessages().getResultCode() == MessageTypeEnum.OK) {
				result.setCode(ResultEntity.SUCCESS_CODE);
				// result.setCardNumber(response.getMessages().g.getAccountNumber());
			} else {
				if (response.getMessages() != null) {
					MessagesType messageType = response.getMessages();
					for (Message message : messageType.getMessage()) {
						errorList.add(message.getText());
					}
					result.setCode(ResultEntity.FAIL_CODE);
				}
			}
		} else {
			if (controller.getErrorResponse() != null) {
				if (controller.getErrorResponse().getMessages() != null) {
					for (Message mess : controller.getErrorResponse().getMessages().getMessage()) {
						errorList.add(mess.getText());
					}
					result.setCode(ResultEntity.FAIL_CODE);
				}
			}

		}

		if (result.getCode().equalsIgnoreCase(ResultEntity.FAIL_CODE)) {
			if (errorList.size() == 0) {
				errorList.add(ERROR_DEFAULT);
			}
			result.setMessage(errorList);
		}
		return result;
	}
}
